
import chisel3._
import chiseltest._
import org.scalatest.{Matchers, FlatSpec}
import scala.util.Random

import comlib.chisel._


class CountersSpec extends FlatSpec with ChiselScalatestTester with Matchers {

    behavior of "Counters"

    val rnd = new Random

    it should "support basic function" in {
        test( new Module {
            val io = IO(new Bundle{
                val inc = Input(Bool())
                val iid = Input(UInt(2.W))
                val ival = Input(UInt(4.W))

                val dec = Input(Bool())
                val did = Input(UInt(2.W))
                val dval = Input(UInt(4.W))

                val cnts = Output(Vec(4, UInt()))
            })
            
            val cnts = Counters( 4, 4 ).inc( io.inc, io.iid, io.ival ).dec( io.dec, io.did, io.dval ).count()

            io.cnts := cnts.cnts
        } ){ dut =>

            // Initial value test
            for( i <- 0 until 4 )
                dut.io.cnts(i).expect( 0.U )

            // Gold Model
            val cnts = Array( 0, 0, 0, 0 )

            // Random
            for( slot <- 0 until 1000 ){

                //---- TC
                val inc = rnd.nextInt(1)==0
                val iid = rnd.nextInt(4)
                val ival = rnd.nextInt(16)

                val dec = rnd.nextInt(1)==0
                val did = rnd.nextInt(4)
                val dval = rnd.nextInt(16)

                //---- RM
                val last = cnts.clone
                if( inc ) cnts(iid) = (ival + cnts(iid)) % 16
                if( dec ) cnts(did) = (16 - dval + cnts(did)) % 16

                //---- Driver
                dut.io.inc.poke( inc.B )
                dut.io.iid.poke( iid.U )
                dut.io.ival.poke( ival.U )
                dut.io.dec.poke( dec.B )
                dut.io.did.poke( did.U )
                dut.io.dval.poke( dval.U )

                //---- Monitor
                dut.clock.step()
                for( i <- 0 until 4 ){
                    dut.io.cnts(i).expect( cnts(i).U, s"Last=${last.mkString("[",",","]")} inc=${inc} iid=${iid} ival=${ival} dec=${dec} did=${did} dval=${dval} i=${i}\n" )
                }
            }
        }
    }

}